import { useEffect, useRef } from 'react';

const AudioVisualizer = () => {
    const rafRef = useRef(0);
    const isUnmoutRef = useRef(false);
    const analyserNodeRef = useRef<AnalyserNode>();
    const audioRef = useRef<HTMLAudioElement>(null);
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const audioContextRef = useRef<AudioContext>();

    const getUserMedia = async () => {
        try {
            const mediaStream = await navigator.mediaDevices.getUserMedia({audio: true});
            audioRef.current!.srcObject = mediaStream;
            /** 音频流输出后再创建音频上下文，这时才能通过媒体流拿到资源节点中对应的数据 */
            const audioContext = new AudioContext();
            const sourceNode = audioContext.createMediaStreamSource(mediaStream);
            const analyserNode = audioContext.createAnalyser();
            sourceNode.connect(analyserNode);
            analyserNode.connect(audioContext.destination);
            analyserNodeRef.current = analyserNode;
            audioContextRef.current = audioContext;
            return true;
        } catch (e) {
            console.log('getUserMedia error: ', e);
        }
    }

    const draw = () => {
        console.log('isUnmoutRef.current: ', isUnmoutRef.current);
        // if (isUnmoutRef.current)    return ;
        rafRef.current = requestAnimationFrame(draw);
        const canvas = canvasRef.current as HTMLCanvasElement;
        const analyserNode = analyserNodeRef.current as AnalyserNode;
        // 获取音频数据
        const dataArray = new Uint8Array(analyserNode.frequencyBinCount);
        analyserNode.getByteFrequencyData(dataArray);

        // 在画布上绘制可视化效果
        const canvasContext = canvas.getContext('2d') as CanvasRenderingContext2D;
        canvasContext.clearRect(0, 0, canvas.width, canvas.height);
        canvasContext.fillStyle = 'rgb(0, 0, 0)';
        canvasContext.fillRect(0, 0, canvas.width, canvas.height);
        canvasContext.fillStyle = 'rgb(255, 255, 255)';
        const barWidth = (canvas.width / dataArray.length) * 2.5;
        let barHeight = 0;
        let x = 0;
        for (let i = 0; i < dataArray.length; i++) {
          barHeight = dataArray[i];
          canvasContext.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight / 2);
          x += barWidth + 1;
        }
    };

    useEffect(() => {
        getUserMedia().then(() => {
            draw();
        });

        return () => {
            isUnmoutRef.current = true;
            audioContextRef.current?.close();
            cancelAnimationFrame(rafRef.current);
        };
    }, []);

    return (
        <div>
            <audio autoPlay ref={audioRef}></audio>
            <canvas ref={canvasRef}></canvas>
        </div>
    );
};

export default AudioVisualizer;
